package com.atserver.vedio;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * @program: atserver
 * @description:
 * @author: Mr.Chen
 * @create: 2023-04-26 01:58
 **/
@Slf4j
public class UsbCameraControlImpl implements UsbCameraControl{

    /** 声明私有对象 **/
    private volatile static UsbCameraControlImpl instance;

    /** 获取实例（单例对象） **/
    public static UsbCameraControlImpl getInstance() {
        // 第一次判断
        if (instance == null) {
            synchronized (UsbCameraControlImpl.class) {
                // 第二次判断
                if (instance == null) {
                    instance = new UsbCameraControlImpl();
                }
            }
        }
        return instance;
    }
    private UsbCameraControlImpl() {
    }

    private final String ffmpegEXE = "./bin/ffmpeg.exe";

    public Process exec = null;
    /**
     * @Description: check the usb camera
     * @Param:
     * @return:
     * @Author: Mr.Chen
     * @Date: 2023/4/26
     */
    @Override
    public Boolean haveUsbCamera() {
        List<String> command = new ArrayList<String>();
        command.add(ffmpegEXE);
        command.add("-list_devices");
        command.add("true");
        command.add("-f");
        command.add("dshow");
        command.add("-i");
        command.add("dummy");

        ProcessBuilder process = new ProcessBuilder();
        process.command(command);
        Process start = null;
        try {
            start = process.start();
        } catch (IOException e) {
            log.error("启动进程错误", e);
        }

        try(BufferedReader readers = new BufferedReader(new InputStreamReader(start.getErrorStream()))) {
            String lines = null;
            while((lines = readers.readLine())!=null) {
                if (lines.contains("Logi C270 HD WebCam")) {
                    log.info("查询到usb摄像头！");
                    return true;
                }
            }
        }catch (Exception e) {
            log.error("获取进程信息错误", e);
        }
        log.info("未查询到usb摄像头！");
        return false;
    }

    /**
     * @param fileName
     * @Description: start usb camera
     * @Param: [fileName]
     * @return: void
     * @Author: Mr.Chen
     * @Date: 2023/4/26
     */
    @Override
    public void doStartCamera(String fileName) {
        String cmd = ffmpegEXE + " -f dshow -i video=\"Logi C270 HD WebCam\" -f dshow -i audio=\"麦克风 (Logi C270 HD WebCam)\" -vcodec libx264 -acodec aac -strict -2 " + fileName;
        List<String> command = StrUtil.split(cmd, " ");

        ProcessBuilder p = new ProcessBuilder();
        p.command(command);
        try {
            exec = p.start();
        } catch (IOException e) {
            log.info("启动进程失败", e);
        }
        try (BufferedReader readers = new BufferedReader(new InputStreamReader(exec.getErrorStream()))){
            String lines1 = null;
            while((lines1 = readers.readLine())!=null) {
                log.info("error lines:"+lines1);
                // 有时候编码的速度太慢导致过多的图片数据保存在缓存内，缓存区空间太小或满了就会报错
                // 需要手动确认一下才能继续
                // 提示信息：xxxtoo full or near too fullxxx
                if (lines1.contains("[y/N]")) {
                    executeCommand("y\n");
                }
            }
        }catch (Exception e) {
            log.error("获取进程信息错误", e);
        }
    }

    /**
     * @Description: close usb camera
     * @Param:
     * @return:
     * @Author: Mr.Chen
     * @Date: 2023/5/3
     */
    @Override
    public boolean endCamera() {
        boolean b = executeCommand("q\n");
        try {
            // 睡眠几秒,让视频流完全写入到视频文件，否则可能会导致文件不可用
            Thread.sleep(3000);
        } catch (Exception e) {

        }
        return b;
    }

    private boolean executeCommand(String command) {
        try {
            OutputStream outputStream = exec.getOutputStream();
            outputStream.write(command.getBytes(StandardCharsets.UTF_8));
            outputStream.flush();
        } catch (Exception e) {
            log.error("执行命令{}错误", command, e);
            return false;
        }
        return true;
    }

}
